# coding=utf-8
from datetime import datetime, timedelta

from common.data import recharge_db
from common.data import withdraw_db
from common.recharge.model import RECHARGE_ORDER_STATUS
from common.utils.exceptions import ParamError
from common.utils.tz import today_str, get_utc_date
from common.withdraw.admin_db import get_all_channel_type
from common.withdraw.model import WITHDRAW_ORDER_STATUS, CHANNEL_TYPE


def get_withdraw_effi_data(group_by, mch_id, started_at, ended_at):
    time_index = _get_time_index(group_by, started_at, ended_at)
    if group_by == 'hourly':
        data_items = withdraw_db.get_withdraw_effi_hourly_data(mch_id, started_at, ended_at)
    else:
        data_items = withdraw_db.get_withdraw_effi_daily_data(mch_id, started_at, ended_at)
    resp = _parse_effi_data('withdraw', group_by, time_index, data_items)
    return resp


def get_recharge_effi_data(group_by, mch_id, started_at, ended_at, pay_type=None):
    time_index = _get_time_index(group_by, started_at, ended_at)
    if group_by == 'hourly':
        data_items = recharge_db.get_recharge_effi_hourly_data(mch_id, started_at, ended_at, pay_type)
    else:
        data_items = recharge_db.get_recharge_effi_daily_data(mch_id, started_at, ended_at, pay_type)
    resp = _parse_effi_data('recharge', group_by, time_index, data_items)
    return resp


def get_withdraw_data(group_by, mch_id, started_at, ended_at):
    time_index = _get_time_index(group_by, started_at, ended_at)
    if group_by == 'hourly':
        data_items = withdraw_db.get_withdraw_hourly_data(mch_id, started_at, ended_at)
    else:
        data_items = withdraw_db.get_withdraw_daily_data(mch_id, started_at, ended_at)
    resp = _parse_data('withdraw', group_by, time_index, data_items)
    return resp


def get_recharge_data(group_by, started_at, ended_at, mch_id, pay_type):
    time_index = _get_time_index(group_by, started_at, ended_at)
    if group_by == 'hourly':
        data_items = recharge_db.get_recharge_hourly_data(started_at, ended_at, mch_id, pay_type)
    else:
        data_items = recharge_db.get_recharge_daily_data(started_at, ended_at, mch_id, pay_type)
    resp = _parse_data('recharge', group_by, time_index, data_items)
    return resp


def _get_time_index(group_by, started_at, ended_at):
    """
    sql group_by 不返回为0的数据, 日期可能不连续
    这里返回一个连续的时间List
    """
    time_index = []
    start = datetime.strptime(started_at, '%Y-%m-%d %H:%M:%S') + timedelta(hours=8)
    end = datetime.strptime(ended_at, '%Y-%m-%d %H:%M:%S') + timedelta(hours=8)
    delta = end - start
    if group_by == 'daily':
        for i in range(delta.days + 1):
            time_index.append((start + timedelta(days=i)).strftime("%Y-%m-%d"))
    elif group_by == 'hourly':
        for i in range(int(delta.total_seconds()) // 3600):
            time_index.append((start + timedelta(hours=i)).strftime("%Y-%m-%d-%H"))
    return time_index


def _parse_data(data_type, group_by, time_index, items):
    """ 将整体数据SQL group by的结果转换为前端需要的格式 """

    # 将查询结果转换为key为time_str的dic
    temp_dic = {}
    for item in items:
        if group_by == 'hourly':
            date, hour, status, count, amount = item
            if hour < 10:
                timestr = date.strftime('%Y-%m-%d-0') + str(hour)
            else:
                timestr = date.strftime('%Y-%m-%d-') + str(hour)

        else:
            date, status, count, amount = item
            timestr = date.strftime('%Y-%m-%d')

        # 将SQL返回的None改为0 显示
        count = 0 if not count else count
        amount = 0 if not amount else amount

        if timestr not in temp_dic:
            temp_dic[timestr] = {
                'amount': 0,
                'total_count': 0,
                'succ_count': 0,
                'fail_count': 0
            }
        if data_type == 'withdraw':
            if status == WITHDRAW_ORDER_STATUS.DONE:
                temp_dic[timestr]['succ_count'] = count
                temp_dic[timestr]['amount'] = float('%.2f' % amount)
            elif status == WITHDRAW_ORDER_STATUS.REJECTED:
                temp_dic[timestr]['fail_count'] = count
            temp_dic[timestr]['total_count'] += count
        elif data_type == 'recharge':
            if status == RECHARGE_ORDER_STATUS.DONE:
                temp_dic[timestr]['succ_count'] = count
                temp_dic[timestr]['amount'] = float('%.2f' % amount)
            elif status == RECHARGE_ORDER_STATUS.REJECTED:
                temp_dic[timestr]['fail_count'] = count
            temp_dic[timestr]['total_count'] += count

    # 将temp_dic转换为前端需要的格式
    resp = dict(amount=[], total_count=[], fail_count=[], amount_avg=[], succ_count=[])
    resp['time'] = time_index
    for timestr in time_index:
        for data_type in ['amount', 'total_count', 'succ_count', 'fail_count']:
            data = temp_dic.get(timestr, {}).get(data_type, 0)
            resp[data_type].append(data)
        amount = temp_dic.get(timestr, {}).get('amount', 0)
        succ_count = temp_dic.get(timestr, {}).get('succ_count', 0)
        amount_avg = 0 if not succ_count else amount // succ_count
        resp['amount_avg'].append(amount_avg)
    return resp


def _parse_effi_data(data_type, group_by, time_index, items):
    ''' 将效率数据SQL group by的结果转换为前端需要的格式 '''

    # 将查询结果转换为key为time_str的dic
    if data_type == "withdraw":
        channel_type_name = CHANNEL_TYPE.to_dict()
        withdraw_channel_types = get_all_channel_type()
    else:
        # MySQL is_null函数return: 1为null, 0为非null
        channel_type_name = {
            0: "人工上分",
            1: "同略云"
        }
    temp_dic = {}
    for item in items:
        if group_by == 'hourly':
            date, hour, third_type, count, total_time = item
            if hour < 10:
                timestr = date.strftime('%Y-%m-%d-0') + str(hour)
            else:
                timestr = date.strftime('%Y-%m-%d-') + str(hour)

        else:
            date, third_type, count, total_time = item
            timestr = date.strftime('%Y-%m-%d')

        # 将SQL返回的None改为0 显示
        total_time = 0 if not total_time else total_time
        count = 0 if not count else count

        if timestr not in temp_dic:
            temp_dic[timestr] = {}
        if data_type == 'withdraw':
            channel_type = withdraw_channel_types.get(third_type)
            if channel_type not in temp_dic[timestr]:
                temp_dic[timestr][channel_type] = {
                    "count": 0,
                    "total_time": 0
                }
            temp_dic[timestr][channel_type]['count'] += count
            temp_dic[timestr][channel_type]['total_time'] += total_time
        elif data_type == 'recharge':
            temp_dic[timestr][third_type] = {
                "count": count,
                "total_time": total_time
            }

    # 将temp_dic转换为前端需要的格式
    resp = {
        'time': time_index
    }
    for timestr in time_index:
        for channel_type, channel_name in channel_type_name.items():
            count = temp_dic.get(timestr, {}).get(channel_type, {}).get('count', 0)
            total_time = temp_dic.get(timestr, {}).get(channel_type, {}).get('total_time', 0)
            avg_time = 0 if count == 0 else int(total_time / count)
            if channel_name not in resp:
                resp[channel_name] = {
                    'avg_time': [],
                    'count': []
                }
            resp[channel_name]['avg_time'].append(avg_time)
            resp[channel_name]['count'].append(count)
    return resp


def get_date_range(query_dct):
    started_at = query_dct.get('started_at', '')
    ended_at = query_dct.get('ended_at', '')
    if not started_at:
        raise ParamError('started_at missed')
    now = datetime.utcnow()
    started_at = get_utc_date(started_at[:10])
    ended_at = get_utc_date(ended_at[:10]) if ended_at else today_str()
    diff = ended_at - started_at
    if diff.days > 90:
        raise ParamError(u'查询时间天数不能大于90天')
    if started_at > now:
        raise ParamError('future is not coming')
    if started_at > ended_at or ended_at > now:
        ended_at = now
    ended_at += timedelta(days=1)
    return str(started_at), str(ended_at)
